﻿#pragma once

#include "common.h"
#include "ui/control_base.h"
#include "ui/button.h"
#include "ui/textfield.h"

namespace anip
{
	namespace ui
	{
		/// <summary>
		/// A generalized slider widget, supports textfield-style editing, warping
		/// and various boundary behaviors.
		/// </summary>
		class Slider : public Control
		{
		private:
			float _min, _max, _val, _startVal = 0;
			bool _slowDrag = false;
			TextField* _edit = nullptr;

			void submitEdit();

		protected:
			void processScroll(invec2 pos) override;
			void processMouseButton(MouseButton btn, ButtonAction action) override;
			void processDefocus() override;

			bool canBeginDrag(MouseButton btn, invec2 pos) override;
			void processDrag(invec2 start, invec2 pos) override;

		public:
			enum class Boundary
			{
				AllowUnderflow,
				AllowOverflow,
				AllowBoth,
				AllowNeither,
				Unbounded
			};

			std::function<void(Slider& self)> onValueChanged;

			/// <summary>
			/// If set to true: specifies a vertical layout.
			/// </summary>
			bool vertical = false;

			/// <summary>
			/// If set to true: rounds the value to the nearest integer whenever 
			/// it changes.
			/// </summary>
			bool integer = false;

			/// <summary>
			/// If set to true: when the value goes out of range, it is warped to 
			/// the other side. Useful for angles etc. Note: only effective when 
			/// boundaryBehavior ==  Boundary::AllowNeither.
			/// </summary>
			bool canWarp = false;

			/// <summary>
			/// If set to true: enables textfield-style editing when clicked.
			/// </summary>
			bool canEdit = true;

			/// <summary>
			/// Specifies whether to allow boundary overflowing, or to be completely
			/// unbounded.
			/// </summary>
			Boundary
				boundaryBehavior = Boundary::AllowNeither;

			bfloat 
				defaultValue = 0, 
				spring = 0;

			bfloat
				pressFactor = r::Button_PressFactor,
				hoverFactor = r::Button_HoverFactor;

			bcolor
				backColor = r::Slider_BackColor,
				foreColor = r::Slider_ForeColor;

			Slider(Container* parent = nullptr, invec2 pos = { 0, 0 }, 
				invec2 size = { 100, 30 }, float min = 0, float max = 1, float val = 0);

			void paint() override;
			void flow(Flow& f) override;

			void setRange(float min, float max);

			// ANIP_TODO: can be splitted to 2 funcs.
			void getRange(float& min, float& max)
			{
				min = _min;
				max = _max;
			}

			float value() { return _val; }

			void setValue(float val);
		};

		class Joystick : public Control
		{
		private:
			Draggable<RoundButton>* _draggy;
			vec2 _val{ 0, 0 };
			
			float _dragSize;

			void _layout();

			static bool _onBeginDrag(Draggable<RoundButton>&, MouseButton, 
				invec2) { return true; }

			static void _onDrag(Draggable<RoundButton>& self, invec2 start, invec2 pos);

		public:
			std::function<void(Joystick& self)> onValueChanged;

			vec2 defaultValue{ 0, 0 };
			float spring = 0;

			bcolor
				backColor = r::Slider_BackColor,
				buttonColor = r::Slider_ForeColor;

			Joystick(Container* parent = nullptr, 
				invec2 pos = { 0, 0 }, invec2 size = { 100, 100 });

			void paint() override;
			void flow(Flow& f) override;

			void setSize(invec2 size) override
			{
				float w = std::min(size.x, size.y);
				Control::setSize({ w, w });
				_layout();
			}

			vec2 value() { return _val; }

			void setValue(invec2 v)
			{
				_val = math::length(v) > 1 ? math::normalize(v) : v;
				_layout();
			}
		};
	}
}